import {
  EventBase,
  IModal,
  Modal,
  OpenAppViewCommand,
  IPanelItemNavPosController,
  ViewMode,
  INavViewMsg,
  NavViewChangeEvent,
} from '@ibiz-template/runtime';
import { IPanelRawItem } from '@ibiz/model-core';
import { RouteLocationNormalizedLoaded, Router } from 'vue-router';
import { PanelItemController } from '../../control';
import { NavPosState } from './nav-pos.state';

/**
 * 导航占位控制器
 *
 * @export
 * @class NavPosController
 * @extends {PanelItemController}
 */
export class NavPosController
  extends PanelItemController<IPanelRawItem>
  implements IPanelItemNavPosController
{
  /**
   * 导航占位状态
   *
   * @type {NavPosState}
   * @memberof NavPosController
   */
  declare state: NavPosState;

  /**
   * 导航视图的modal
   *
   * @type {{ [key: string]: IModal }}
   * @memberof NavPosController
   */
  viewModals: { [key: string]: IModal } = {};

  /**
   * 当前导航视图
   *
   * @type {INavViewMsg}
   * @memberof NavPosController
   */
  curNavViewMsg!: INavViewMsg;

  /**
   * Router 对象
   *
   * @type {Router}
   * @memberof NavPosController
   */
  router!: Router;

  /**
   * 关联部件标识集合
   * @author lxm
   * @date 2023-08-10 07:35:08
   * @type {string[]}
   */
  refCtrlKeys: string[] = [];

  /**
   * Route 对象
   *
   * @author zk
   * @date 2023-06-29 04:06:59
   * @type {RouteLocationNormalizedLoaded}
   * @memberof NavPosController
   */
  get route(): RouteLocationNormalizedLoaded {
    return this.router.currentRoute.value;
  }

  /**
   * 设置 Router 对象
   *
   * @param {Router} router
   * @memberof NavPosController
   */
  setRouter(router: Router): void {
    this.router = router;
  }

  protected async onInit(): Promise<void> {
    await super.onInit();

    if (this.model.rawItem?.rawItemParams) {
      this.model.rawItem.rawItemParams.find(item => {
        if (item.key === 'REFCTRL' && item.value) {
          this.refCtrlKeys = item.value
            .split(';')
            .map(str => str.toLowerCase());
          return true;
        }
        return false;
      });
    }

    this.panel.evt.on('onControlEvent', event => {
      // 是否是关联部件，如果没有配置都监控，配置了只监控指定部件
      const isRefCtrl =
        this.refCtrlKeys.length === 0 ||
        this.refCtrlKeys.includes(event.triggerControlName);
      if (isRefCtrl && event.triggerEventName === 'onNavViewChange') {
        const triggerEvent = event.triggerEvent as NavViewChangeEvent;
        this.openView(triggerEvent.navViewMsg);
      }
    });
  }

  /**
   * 创建导航占位状态对象
   *
   * @protected
   * @return {*}  {NavPosState}
   * @memberof NavPosController
   */
  protected createState(): NavPosState {
    return new NavPosState(this.parent?.state);
  }

  /**
   * 当前路由视图的层级
   *
   * @readonly
   * @type {(number | undefined)}
   * @memberof NavPosController
   */
  get routeDepth(): number | undefined {
    return this.panel.view.modal.routeDepth;
  }

  /**
   * 路由改变
   *
   * @memberof NavPosController
   */
  onRouteChange(route: RouteLocationNormalizedLoaded): void {
    // 没有当前导航视图信息时不做任何处理
    if (this.curNavViewMsg) {
      // 路由打开的视图，currentKey在路由变更之后改值。此时新建的视图才能识别到跳转之后的路由。
      this.state.currentKey = this.curNavViewMsg.key;

      // 更新fullPath信息
      this.state.navViewMsgs[this.curNavViewMsg.key].fullPath = route.fullPath;
    }
  }

  /**
   * 设置导航视图信息
   *
   * @author zk
   * @date 2023-06-29 02:06:41
   * @param {INavViewMsg} navViewMsg 导航视图信息
   * @memberof NavPosController
   */
  setNavViewMsgs(navViewMsg: INavViewMsg): void {
    // 已经存在的更新数据
    if (this.state.navViewMsgs[navViewMsg.key]) {
      this.state.navViewMsgs[navViewMsg.key] = Object.assign(
        this.state.navViewMsgs[navViewMsg.key],
        navViewMsg,
      );
    } else {
      // 不存在的走新建流程
      this.state.navViewMsgs[navViewMsg.key] = navViewMsg;
      // 往缓存keys里添加新视图的key
      this.state.cacheKeys.push(navViewMsg.key);
      this.viewModals[navViewMsg.key] = new Modal({
        mode: this.routeDepth ? ViewMode.ROUTE : ViewMode.EMBED,
        routeDepth: this.routeDepth ? this.routeDepth + 1 : undefined,
        dismiss: () => {
          // 执行对应key的dismiss方法
          this.dismiss(navViewMsg.key);
        },
      });
    }

    // todo 换个方式
    this.curNavViewMsg = this.state.navViewMsgs[navViewMsg.key];
  }

  /**
   * 自身的dismiss相关操作
   *
   * @param {string} key
   * @memberof NavPosController
   */
  dismiss(key: string): void {
    ibiz.log.debug(this.constructor.name, 'dismiss', key);
  }

  /**
   * 监听视图创建
   *
   * @param {EventBase} event
   * @memberof NavPosController
   */
  onViewCreated(event: EventBase): void {
    ibiz.log.debug(this.constructor.name, 'onViewCreated', event);
  }

  /**
   * 打开视图
   *
   * @param {INavViewMsg} openViewMsg
   * @memberof NavPosController
   */
  openView(openViewMsg: INavViewMsg): void {
    if (this.routeDepth) {
      this.openViewByPath(openViewMsg);
    } else {
      this.openViewByModel(openViewMsg);
    }
  }

  /**
   * 通过路由打开视图
   *
   * @param {INavViewMsg} openViewMsg
   * @memberof NavPosController
   */
  openViewByPath(openViewMsg: INavViewMsg): void {
    const isFirstOpen = Object.values(this.state.navViewMsgs).length === 0;
    this.setNavViewMsgs(openViewMsg);
    // * 首次打开时,如果当前路由层级已经大于导航视图的层级，说明是浏览器带深层路径刷新的场景，不需要push路由，直接处理后续内容。
    if (isFirstOpen && this.route.matched.length > this.routeDepth!) {
      this.state.currentKey = openViewMsg.key;
      this.state.navViewMsgs[this.curNavViewMsg.key].fullPath =
        this.route.fullPath;
      return;
    }

    // * 路由跳转
    // 如果启用缓存并且有之前存过的fullPath则push回fullPath。
    if (this.state.cache && this.state.navViewMsgs[openViewMsg.key].fullPath) {
      this.router.push(this.state.navViewMsgs[openViewMsg.key].fullPath!);
    } else {
      // 走视图路由打开逻辑计算并push
      const tempContext = Object.assign(openViewMsg.context!.clone(), {
        toRouteDepth: this.routeDepth! + 1,
      });
      this.state.cacheKeys.push(openViewMsg.key);
      ibiz.commands.execute(
        OpenAppViewCommand.TAG,
        openViewMsg.viewId,
        tempContext,
        openViewMsg.params,
        { openMode: 'INDEXVIEWTAB' },
      );
    }

    // !跳转路由过后，修改currentKey由onRouteChange那边路由变更之后处理。
  }

  /**
   * 通过模型绘制视图
   *
   * @param {INavViewMsg} openViewMsg
   * @memberof NavPosController
   */
  openViewByModel(openViewMsg: INavViewMsg): void {
    this.setNavViewMsgs(openViewMsg);
    // 切换currentKey，重新渲染openViewMsg
    this.state.currentKey = openViewMsg.key;
  }
}
